namespace ts {
    /* @internal */
    export const compileOnSaveCommandLineOption: CommandLineOption = { name: "保存时编译", type: "boolean" };

    /* @internal */
    export const 选项声明组: CommandLineOption[] = [
        {
            name: '构建',
            shortName: 'b',
            type: 'boolean',
            showInSimplifiedHelpView: true,
            isCommandLineOnly: true,
            category: Diagnostics.命令行选项,
            description: Diagnostics.构建项目并生成诊断,
        },
        {
            name: '帮助',
            shortName: 'h',
            type: 'boolean',
            showInSimplifiedHelpView: true,
            isCommandLineOnly: true,
            category: Diagnostics.命令行选项,
            description: Diagnostics.打印帮助消息,
        },
        {
            name: '版本号',
            shortName: 'v',
            type: 'boolean',
            showInSimplifiedHelpView: true,
            isCommandLineOnly: true,
            category: Diagnostics.命令行选项,
            description: Diagnostics.输出编译器版本号,
        },
        {
            name: '初始',
            shortName: 'init',
            type: 'boolean',
            showInSimplifiedHelpView: true,
            isCommandLineOnly: true,
            category: Diagnostics.命令行选项,
            description: Diagnostics.初始一个_Klang_项目_并创建了一个_kconfig_json_文件,
        },
        {
            name: '监控',
            shortName: 'w',
            type: 'boolean',
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.监控输入文件,
        },
        {
            name: '启用诊断',
            shortName: 'w',
            type: 'boolean',
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.启用诊断,
        },
        {
            name: '系统',
            shortName: 'os',
            type: createMapFromTemplate({
                'win': 'win',
                'win32':'win32',
                'win64':'win64',
                'linux': 'linux',
                'darwin': 'darwin',
            }),
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置源码编译目标系统,
        },
        {
            name: '架构',
            shortName: 'a',
            type: createMapFromTemplate({
                '368': '386',
                'amd64': 'amd64',
                'arm': 'arm'
            }),
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置源码编译目标架构,
        },
        {
            name: '输出类型',
            type: createMapFromTemplate({
                'exe': 'exe',
                'lib': 'lib',
                'dll': 'dll'
            }),
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置输出类型,
        },
        {
            name: '输出模式',
            type: createMapFromTemplate({
                'debug': 'debug',
                'release': 'release',
                'unittest': 'unittest'
            }),
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置输出模式,
        },
        {
            name: '定义',
            shortName: 'env',
            type: 'list',
            element: {
                name: '定义',
                type: 'string',
            },
            paramType: Diagnostics.选项,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置环境变量数组,
        },
        {
            name: '输出',
            shortName: 'o',
            type: 'string',
            paramType: Diagnostics.选项,
            isFilePath: true,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.输出到这个目录,
        },
        {
            name: '源码',
            type: 'string',
            paramType: Diagnostics.选项,
            isFilePath: true,
            showInSimplifiedHelpView: true,
            category: Diagnostics.基本编译选项,
            description: Diagnostics.设置源码根目录_默认为_Slash源码,
        },
        {
            name: '名称',
            type: 'string',
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.项目名称_例如_klangapp,
            是项目配置: true
        },
        {
            name: '描述',
            type: 'string',
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.项目简介,
            是项目配置: true
        },
        {
            name: '版本',
            type: 'string',
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.目前版本号,
            是项目配置: true
        },
        {
            name: '主页',
            type: 'string',
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.项目主页,
            是项目配置: true
        },
        {
            name: '作者',
            type: 'object',
            elementOptions: createMapFromTemplate({
                姓名: {
                    name: '姓名',
                    type: 'string',
                    paramType: Diagnostics.选项,
                    category: Diagnostics.项目配置,
                    description: Diagnostics.开发者姓名,

                },
                公司: {
                    name: '公司',
                    type: 'string',
                    paramType: Diagnostics.选项,
                    category: Diagnostics.项目配置,
                    description: Diagnostics.开发公司,
                },
                邮箱: {
                    name: '邮箱',
                    type: 'string',
                    paramType: Diagnostics.选项,
                    category: Diagnostics.项目配置,
                    description: Diagnostics.公开邮箱,
                },
                博客: {
                    name: '博客',
                    type: 'string',
                    paramType: Diagnostics.选项,
                    category: Diagnostics.项目配置,
                    description: Diagnostics.公开博客,
                }
            }),
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.开发单位,
            是项目配置: true
        },
        {
            name: '贡献',
            type: 'list',
            element: {
                name: '作者',
                type: 'object',
                elementOptions: createMapFromTemplate({
                    姓名: {
                        name: '姓名',
                        type: 'string',
                        paramType: Diagnostics.选项,
                        category: Diagnostics.项目配置,
                        description: Diagnostics.开发者姓名,

                    },
                    公司: {
                        name: '公司',
                        type: 'string',
                        paramType: Diagnostics.选项,
                        category: Diagnostics.项目配置,
                        description: Diagnostics.开发公司,
                    },
                    邮箱: {
                        name: '邮箱',
                        type: 'string',
                        paramType: Diagnostics.选项,
                        category: Diagnostics.项目配置,
                        description: Diagnostics.公开邮箱,
                    },
                    博客: {
                        name: '博客',
                        type: 'string',
                        paramType: Diagnostics.选项,
                        category: Diagnostics.项目配置,
                        description: Diagnostics.公开博客,
                    }
                }),
                paramType: Diagnostics.选项,
                category: Diagnostics.项目配置,
                description: Diagnostics.开发单位,
            },
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.贡献者名单,
            是项目配置: true
        },
        {
            name: '依赖',
            type: "object",
            paramType: Diagnostics.选项,
            category: Diagnostics.项目配置,
            description: Diagnostics.外部依赖模块名称及版本,
            是项目配置: true
        }
    ];
    /* @internal */
    export interface OptionNameMap {
        optionNameMap: Map<CommandLineOption>;
        shortOptionNames: Map<string>;
    }

    /* @internal */
    export const defaultInitCompilerOptions: CompilerOptions = {
        系统: 'win',
        架构: 'amd64',
        输出: './输出' as Path,
        源码: './源码' as Path,
        输出模式: "unittest",
        输出类型: "lib",
        监控: true,
        启用诊断: true,
        定义: ['__WIN__']
    };

    export const 默认项目配置选项 = {
        名称: 'klangApp',
        版本: '0.0.1',
        主页: 'gitee.com/xxx/xxxx',
        依赖: {}
    }

    /* @internal */
    export const buildOpts: CommandLineOption[] = [
        ...选项声明组,
        {
            name: "详细",
            shortName: "ver",
            category: Diagnostics.命令行选项,
            description: Diagnostics.启用详细日志,
            type: "boolean"
        },
        {
            name: "清屏",
            shortName: "d",
            category: Diagnostics.命令行选项,
            description: Diagnostics.显示将生成的内容_如果使用_清除_指定_则删除,
            type: "boolean"
        },
        {
            name: "强制",
            shortName: "f",
            category: Diagnostics.命令行选项,
            description: Diagnostics.强制构建所有项目,
            type: "boolean"
        },
        {
            name: "清除",
            category: Diagnostics.命令行选项,
            description: Diagnostics.删除所有项目的输出,
            type: "boolean"
        }
    ];
    export const optionDeclarations = buildOpts;

    let optionNameMapCache: OptionNameMap;

    /* @internal */
    export function getOptionNameMap(): OptionNameMap {
        return optionNameMapCache || (optionNameMapCache = createOptionNameMap(buildOpts));
    }

    /*@internal*/
    export function createOptionNameMap(optionDeclarations: readonly CommandLineOption[]): OptionNameMap {
        const optionNameMap = createMap<CommandLineOption>();
        const shortOptionNames = createMap<string>();
        forEach(optionDeclarations, option => {
            optionNameMap.set(option.name.toLowerCase(), option);
            if (option.shortName) {
                shortOptionNames.set(option.shortName, option.name);
            }
        });

        return { optionNameMap, shortOptionNames };
    }

    /* @internal */
    export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic {
        return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic);
    }

    function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic): Diagnostic {
        const namesOfType = arrayFrom(opt.type.keys()).map(key => `'${key}'`).join(", ");
        return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType);
    }

    /* @internal */
    export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) {
        return convertJsonOptionOfCustomType(opt, trimString(value || ""), errors);
    }

    /* @internal */
    export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): (string | number)[] | undefined {
        value = trimString(value);
        if (startsWith(value, "-")) {
            return undefined;
        }
        if (value === "") {
            return [];
        }
        const values = value.split(",");
        switch (opt.element.type) {
            case "number":
                return map(values, parseInt);
            case "string":
                return map(values, v => v || "");
            default:
                return mapDefined(values, v => parseCustomTypeOption(<CommandLineOptionOfCustomType>opt.element, v, errors));
        }
    }

    interface OptionsBase {
        [option: string]: CompilerOptionsValue | undefined;
    }

    /** Tuple with error messages for 'unknown compiler option', 'option requires type' */
    type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage];

    function parseCommandLineWorker(
        getOptionNameMap: () => OptionNameMap,
        [unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics,
        commandLine: readonly string[],
        readFile?: (path: string) => string | undefined) {
        let options = {} as OptionsBase;
        const errors: Diagnostic[] = [];
        parseStrings(commandLine);
        let 配置目录: string;
        let fileNames = 获取项目文件组(options)
        if (!options || !fileNames.length) {
            if (配置目录! && readFile) {
                const path = isAnySupportedFileExtension(配置目录!) ? getDirectoryPath(配置目录!) : normalizePath(配置目录!);
                const fileName = getNormalizedAbsolutePath(combinePaths(path, "kconfig.json"), sys.getCurrentDirectory());
                const json = parseJsonText(fileName, readFile(fileName) || "{}")
                return parseJsonSourceFileConfigFileContent(json, path)
            }
        }
        return {
            options,
            fileNames,
            errors,
            全局模块位置: sys.getEnvironmentVariable("KLANG_MOD")
        };

        function parseStrings(args: readonly string[]) {
            let i = 0;
            while (i < args.length) {
                const s = args[i];
                i++;
                if (s.charCodeAt(0) === Charas.at) {
                    parseResponseFile(s.slice(1));
                }
                else if (s.charCodeAt(0) === Charas.minus) {
                    const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === Charas.minus ? 2 : 1), /*allowShort*/ true);
                    if (opt) {
                        if (opt.isTSConfigOnly) {
                            errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
                        }
                        else {
                            // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
                            if (!args[i] && opt.type !== "boolean") {
                                errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name));
                            }

                            switch (opt.type) {
                                case "number":
                                    options[opt.name] = parseInt(args[i]);
                                    i++;
                                    break;
                                case "boolean":
                                    // boolean flag has optional value true, false, others
                                    const optValue = args[i];
                                    options[opt.name] = optValue !== "false";
                                    // consume next argument as boolean flag value
                                    if (optValue === "false" || optValue === "true") {
                                        i++;
                                    }
                                    break;
                                case "string":
                                    options[opt.name] = args[i] || "";
                                    i++;
                                    break;
                                case "list":
                                    const result = parseListTypeOption(opt, args[i], errors);
                                    options[opt.name] = result || [];
                                    if (result) {
                                        i++;
                                    }
                                    break;
                                // If not a primitive, the possible types are specified in what is effectively a map of options.
                                default:
                                    options[opt.name] = parseCustomTypeOption(<CommandLineOptionOfCustomType>opt, args[i], errors);
                                    i++;
                                    break;
                            }
                        }
                    }
                    else {
                        errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s));
                    }
                }
                配置目录 = s;
            }
        }

        function parseResponseFile(fileName: string) {
            const text = readFile ? readFile(fileName) : sys.readFile(fileName);

            if (!text) {
                errors.push(createCompilerDiagnostic(Diagnostics.没发现文件_0, fileName));
                return;
            }

            const args: string[] = [];
            let pos = 0;
            while (true) {
                while (pos < text.length && text.charCodeAt(pos) <= Charas.space) pos++;
                if (pos >= text.length) break;
                const start = pos;
                if (text.charCodeAt(start) === Charas.doubleQuote) {
                    pos++;
                    while (pos < text.length && text.charCodeAt(pos) !== Charas.doubleQuote) pos++;
                    if (pos < text.length) {
                        args.push(text.substring(start + 1, pos));
                        pos++;
                    }
                    else {
                        errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName));
                    }
                }
                else {
                    while (text.charCodeAt(pos) > Charas.space) pos++;
                    args.push(text.substring(start, pos));
                }
            }
            parseStrings(args);
        }
    }

    export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine {
        return parseCommandLineWorker(getOptionNameMap, [
            Diagnostics.Unknown_compiler_option_0,
            Diagnostics.Compiler_option_0_expects_an_argument
        ], commandLine, readFile);
    }

    /** @internal */
    export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
        return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
    }

    function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
        optionName = optionName.toLowerCase();
        const { optionNameMap, shortOptionNames } = getOptionNameMap();
        // Try to translate short option names to their full equivalents.
        if (allowShort) {
            const short = shortOptionNames.get(optionName);
            if (short !== undefined) {
                optionName = short;
            }
        }
        return optionNameMap.get(optionName);
    }

    /*@internal*/
    export interface ParsedBuildCommand {
        buildOptions: BuildOptions;
        errors: Diagnostic[];
    }

    /*@internal*/
    export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand {
        let buildOptionNameMap: OptionNameMap | undefined;
        const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
        const { options, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
            Diagnostics.Unknown_build_option_0,
            Diagnostics.Build_option_0_requires_a_value_of_type_1
        ], args, sys.readFile);
        const buildOptions = options as BuildOptions;

        // Nonsensical combinations
        if (buildOptions.清除 && buildOptions.强制) {
            errors.push(createCompilerDiagnostic(Diagnostics.选项_0_和_1_不能同时存在, "清除", "强制"));
        }
        if (buildOptions.清除 && buildOptions.详细) {
            errors.push(createCompilerDiagnostic(Diagnostics.选项_0_和_1_不能同时存在, "清除", "详细"));
        }
        if (buildOptions.清除 && buildOptions.监控) {
            errors.push(createCompilerDiagnostic(Diagnostics.选项_0_和_1_不能同时存在, "清除", "监控"));
        }
        if (buildOptions.监控 && buildOptions.清屏) {
            errors.push(createCompilerDiagnostic(Diagnostics.选项_0_和_1_不能同时存在, "监控", "清屏"));
        }

        return { buildOptions, errors };
    }

    /* @internal */
    export function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
        const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
        return <string>diagnostic.messageText;
    }

    export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
    /**
     * Reports config file diagnostics
     */
    export interface ConfigFileDiagnosticsReporter {
        /**
         * Reports unrecoverable error when parsing config file
         */
        onUnRecoverableConfigFileDiagnostic: DiagnosticReporter;
    }

    /**
     * Interface extending ParseConfigHost to support ParseConfigFile that reads config file and reports errors
     */
    export interface ParseConfigFileHost extends ParseConfigHost, ConfigFileDiagnosticsReporter {
        getCurrentDirectory(): string;
    }

    /**
     * Reads the config file, reports errors if any and exits if the config file cannot be found
     */
    export function getParsedCommandLineOfConfigFile(
        configFileName: string,
        optionsToExtend: CompilerOptions,
        host: ParseConfigFileHost
    ): ParsedCommandLine | undefined {
        let configFileText: string | undefined;
        try {
            configFileText = host.readFile(configFileName);
        }
        catch (e) {
            const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message);
            host.onUnRecoverableConfigFileDiagnostic(error);
            return undefined;
        }
        if (!configFileText) {
            const error = createCompilerDiagnostic(Diagnostics.没发现文件_0, configFileName);
            host.onUnRecoverableConfigFileDiagnostic(error);
            return undefined;
        }

        const result = parseJsonText(configFileName, configFileText);
        const cwd = host.getCurrentDirectory();
        result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames));
        result.resolvedPath = result.path;
        result.originalFileName = result.fileName;
        return parseJsonSourceFileConfigFileContent(
            result,
            getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd),
            optionsToExtend,
            getNormalizedAbsolutePath(configFileName, cwd));
    }

    /**
     * Read tsconfig.json file
     * @param fileName The path to the config file
     */
    export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } {
        const textOrDiagnostic = tryReadFile(fileName, readFile);
        return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
    }

    /**
     * Parse the text of the tsconfig.json file
     * @param fileName The path to the config file
     * @param jsonText The text of the config file
     */
    export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } {
        const jsonSourceFile = parseJsonText(fileName, jsonText);
        return {
            config: convertToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics),
            error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined
        };
    }

    /**
     * Read tsconfig.json file
     * @param fileName The path to the config file
     */
    export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): TsConfigSourceFile {
        const textOrDiagnostic = tryReadFile(fileName, readFile);
        return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : <TsConfigSourceFile>{ parseDiagnostics: [textOrDiagnostic] };
    }

    function tryReadFile(fileName: string, readFile: (path: string) => string | undefined): string | Diagnostic {
        let text: string | undefined;
        try {
            text = readFile(fileName);
        }
        catch (e) {
            return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message);
        }
        return text === undefined ? createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, fileName) : text;
    }

    function commandLineOptionsToMap(options: readonly CommandLineOption[]) {
        return arrayToMap(options, option => option.name);
    }

    let _tsconfigRootOptions: TsConfigOnlyOption;
    function getTsconfigRootOptionsMap() {
        if (_tsconfigRootOptions === undefined) {
            _tsconfigRootOptions = {
                name: undefined!, // should never be needed since this is root
                type: "object",
                elementOptions: commandLineOptionsToMap([
                    {
                        name: "编译选项",
                        type: "object",
                        elementOptions: commandLineOptionsToMap(buildOpts),
                        extraKeyDiagnosticMessage: Diagnostics.Unknown_compiler_option_0
                    },
                    compileOnSaveCommandLineOption
                ])
            };
        }
        return _tsconfigRootOptions;
    }

    /*@internal*/
    interface JsonConversionNotifier {
        /**
         * Notifies parent option object is being set with the optionKey and a valid optionValue
         * Currently it notifies only if there is element with type object (parentOption) and
         * has element's option declarations map associated with it
         * @param parentOption parent option name in which the option and value are being set
         * @param option option declaration which is being set with the value
         * @param value value of the option
         */
        onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue): void;
    }

    /**
     * Convert the json syntax tree into the json value
     */
    export function convertToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>): any {
        return convertToObjectWorker(sourceFile, errors, /*returnValue*/ true, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
    }

    /**
     * Convert the json syntax tree into the json value and report errors
     * This returns the json value (apart from checking errors) only if returnValue provided is true.
     * Otherwise it just checks the errors and returns undefined
     */
    /*@internal*/
    export function convertToObjectWorker(
        sourceFile: JsonSourceFile,
        errors: Push<Diagnostic>,
        returnValue: boolean,
        knownRootOptions: CommandLineOption | undefined,
        jsonConversionNotifier: JsonConversionNotifier | undefined): any {
        if (!sourceFile.statements.length) {
            return returnValue ? {} : undefined;
        }

        return convertPropertyValueToJson(sourceFile.statements[0].expression, knownRootOptions);

        function isRootOptionMap(knownOptions: Map<CommandLineOption> | undefined) {
            return knownRootOptions && (knownRootOptions as TsConfigOnlyOption).elementOptions === knownOptions;
        }

        function convertObjectLiteralExpressionToJson(
            node: ObjectLiteralExpression,
            knownOptions: Map<CommandLineOption> | undefined,
            extraKeyDiagnosticMessage: DiagnosticMessage | undefined,
            parentOption: string | undefined
        ): any {
            const result: any = returnValue ? {} : undefined;
            for (const element of node.properties) {
                if (element.kind !== SyntaxKind.PropertyAssignment) {
                    errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected));
                    continue;
                }

                if (element.questionToken) {
                    errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.questionToken, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
                }
                if (!isDoubleQuotedString(element.name)) {
                    errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, Diagnostics.String_literal_with_double_quotes_expected));
                }

                const textOfKey = getTextOfPropertyName(element.name);
                const keyText = textOfKey && textOfKey;
                const option = keyText && knownOptions ? knownOptions.get(keyText) : undefined;
                if (keyText && extraKeyDiagnosticMessage && !option) {
                    errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnosticMessage, keyText));
                }
                const value = convertPropertyValueToJson(element.initializer, option);
                if (typeof keyText !== "undefined") {
                    if (returnValue) {
                        result[keyText] = value;
                    }
                    // Notify key value set, if user asked for it
                    if (jsonConversionNotifier &&
                        // Current callbacks are only on known parent option or if we are setting values in the root
                        (parentOption || isRootOptionMap(knownOptions))) {
                        const isValidOptionValue = isCompilerOptionsValue(option, value);
                        if (parentOption) {
                            if (isValidOptionValue) {
                                // Notify option set in the parent if its a valid option value
                                jsonConversionNotifier.onSetValidOptionKeyValueInParent(parentOption, option!, value);
                            }
                        }
                    }
                }
            }
            return result;
        }

        function convertArrayLiteralExpressionToJson(
            elements: NodeArray<Expression>,
            elementOption: CommandLineOption | undefined
        ): any[] | void {
            if (!returnValue) {
                return elements.forEach(element => convertPropertyValueToJson(element, elementOption));
            }

            // Filter out invalid values
            return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined);
        }

        function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any {
            switch (valueExpression.kind) {
                case SyntaxKind.TrueKeyword:
                    reportInvalidOptionValue(option && option.type !== "boolean");
                    return true;

                case SyntaxKind.FalseKeyword:
                    reportInvalidOptionValue(option && option.type !== "boolean");
                    return false;

                case SyntaxKind.NullKeyword:
                    reportInvalidOptionValue(option && option.name === "extends"); // "extends" is the only option we don't allow null/undefined for
                    return null; // eslint-disable-line no-null/no-null

                case SyntaxKind.StringLiteral:
                    if (!isDoubleQuotedString(valueExpression)) {
                        errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected));
                    }
                    reportInvalidOptionValue(option && (isString(option.type) && option.type !== "string"));
                    const text = (<StringLiteral>valueExpression).text;
                    if (option && !isString(option.type)) {
                        const customOption = <CommandLineOptionOfCustomType>option;
                        // Validate custom option type
                        if (!customOption.type.has(text.toLowerCase())) {
                            errors.push(
                                createDiagnosticForInvalidCustomType(
                                    customOption,
                                    (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, message, arg0, arg1)
                                )
                            );
                        }
                    }
                    return text;

                case SyntaxKind.NumericLiteral:
                    reportInvalidOptionValue(option && option.type !== "number");
                    return Number((<NumericLiteral>valueExpression).text);

                case SyntaxKind.PrefixUnaryExpression:
                    if ((<PrefixUnaryExpression>valueExpression).operator !== SyntaxKind.MinusToken || (<PrefixUnaryExpression>valueExpression).operand.kind !== SyntaxKind.NumericLiteral) {
                        break; // not valid JSON syntax
                    }
                    reportInvalidOptionValue(option && option.type !== "number");
                    return -Number((<NumericLiteral>(<PrefixUnaryExpression>valueExpression).operand).text);

                case SyntaxKind.ObjectLiteralExpression:
                    reportInvalidOptionValue(option && option.type !== "object");
                    const objectLiteralExpression = <ObjectLiteralExpression>valueExpression;

                    // Currently having element option declaration in the tsconfig with type "object"
                    // determines if it needs onSetValidOptionKeyValueInParent callback or not
                    // At moment there are only "compilerOptions", "typeAcquisition" and "typingOptions"
                    // that satifies it and need it to modify options set in them (for normalizing file paths)
                    // vs what we set in the json
                    // If need arises, we can modify this interface and callbacks as needed
                    if (option) {
                        const { elementOptions, extraKeyDiagnosticMessage, name: optionName } = <TsConfigOnlyOption>option;
                        return convertObjectLiteralExpressionToJson(objectLiteralExpression,
                            elementOptions, extraKeyDiagnosticMessage, optionName);
                    }
                    else {
                        return convertObjectLiteralExpressionToJson(
                            objectLiteralExpression, /* knownOptions*/ undefined,
                            /*extraKeyDiagnosticMessage */ undefined, /*parentOption*/ undefined);
                    }

                case SyntaxKind.ArrayLiteralExpression:
                    reportInvalidOptionValue(option && option.type !== "list");
                    return convertArrayLiteralExpressionToJson(
                        (<ArrayLiteralExpression>valueExpression).elements,
                        option && (<CommandLineOptionOfListType>option).element);
            }

            // Not in expected format
            if (option) {
                reportInvalidOptionValue(/*isError*/ true);
            }
            else {
                errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal));
            }

            return undefined;

            function reportInvalidOptionValue(isError: boolean | undefined) {
                if (isError) {
                    errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, option!.name, getCompilerOptionValueTypeString(option!)));
                }
            }
        }

        function isDoubleQuotedString(node: Node): boolean {
            return isStringLiteral(node) && isStringDoubleQuoted(node, sourceFile);
        }
    }

    function getCompilerOptionValueTypeString(option: CommandLineOption) {
        return option.type === "list" ?
            "Array" :
            isString(option.type) ? option.type : "string";
    }

    function isCompilerOptionsValue(option: CommandLineOption | undefined, value: any): value is CompilerOptionsValue {
        if (option) {
            if (isNullOrUndefined(value)) return true; // All options are undefinable/nullable
            if (option.type === "list") {
                return isArray(value);
            }
            const expectedType = isString(option.type) ? option.type : "string";
            return typeof value === expectedType;
        }
        return false;
    }

    /** @internal */
    export interface TSConfig {
        选项: CompilerOptions;
        保存时编译: boolean | undefined
    }

    export interface KlangModConfig {
        名称: string;
        概述: string;
        版本: string;
        主页: string;
        版权: string;
        许可: string;
        作者: { [k: string]: string }
        依赖: { [k: string]: string }
        [k: string]: any
    }

    export interface DlangDubConfig {
        name: string;                     // Name of the package, used to uniquely identify the package.Must be comprised of only lower case ASCII alpha - numeric characters, "-" or "_".
        description?: string;              //[required for publishing]string	Brief description of the package
        toolchainRequirements?: string[];  // Set of version requirements for DUB, for compilers and for language frontend.See the toolchain requirements section.
        homepage?: string;                 // URL of the project website
        authors?: { [k: string]: string };                // List of project authors(the suggested format is either "Peter Parker" or "Peter Parker <pparker@example.com>")
        copyright?: string;                // Copyright declaration string
        license?: string;                  // [required for publishing]string	License(s) under which the project can be used - see the license specification section for possible values
        subPackages?: DlangBuildSettings[];                  // T[] Defines an array of sub - packages defined in the same directory as the root project, where each entry is either a path of a sub folder or an object of the same formatas a dub.json file - see the sub package section for more information
        configurations?: DlangBuildSettings[];               // T[] Speficies an optional list of build configurations(chosen on the command line using--config =...) - see the configurations section for more details
        buildTypes?: BuildTypes;
    }

    export type DlangBuildRequirements = "allowWarnings" | "silenceWarnings" | "disallowDeprecations" |
        "silenceDeprecations" | "disallowInlining" | "disallowOptimization" | "requireBoundsCheck" |
        "requireContracts" | "relaxProperties" | "noDefaultFlags";

    export type DlangBuildOptions = "debugMode" | "releaseMode" | "coverage" |
        "debugInfo" | "debugInfoC" | "alwaysStackFrame" | "stackStomping" |
        "inline" | "noBoundsCheck" | "optimize" | "profile" | "profileGC" |
        "unittests" | "verbose" | "ignoreUnknownPragmas" | "syntaxOnly" |
        "warnings" | "warningsAsErrors" | "ignoreDeprecations" | "deprecationWarnings" |
        "deprecationErrors" | "property" | "betterC";

    export type ToolchainRequirements = "dub" | "frontend" | "dmd" | "ldc";

    export type TargetTypes = "autodetect" | "none" | "executable" | "library" |
        "sourceLibrary" | "staticLibrary" | "dynamicLibrary"

    export type BuildTypes = {
        [k: string]: {
            [k: string]: DlangBuildOptions[]
        }
    }

    export interface DlangBuildSettings {
        name: string
        platforms?: string[]
        dependencies?: string                        // List of project dependencies given as pairs of "<name>" : <version-spec> - see next section for how version specifications look like - this setting does not support platform suffixes
        systemDependencies?: string                    // A textual description of the required system dependencies (external C libraries) required by the package. This will be visible on the registry and will be displayed in case of linker errors - this setting does not support platform suffixes
        targetType?: TargetTypes                            // Specifies a specific target type - this setting does not support platform suffixes
        targetName?: string                            // Sets the base name of the output file; type and platform specific pre- and suffixes are added automatically - this setting does not support platform suffixes
        targetPath?: string                            // The destination path of the output binary - this setting does not support platform suffixes
        workingDirectory?: string                      // A fixed working directory from which the generated executable will be run - this setting does not support platform suffixes
        subConfigurations?: string[]                    // Locks the dependencies to specific configurations; a map from package name to configuration name, see also the configurations section - this setting does not support platform suffixes
        buildRequirements?: DlangBuildRequirements[]                   // List of required settings for the build process. See the build requirements section for details.
        buildOptions?: DlangBuildOptions[]                        // List of build option identifiers (corresponding to compiler flags) - see the build options section for details.
        libs?: string[]                                // A list of external library names - depending on the compiler, these will be converted to the proper linker flag (e.g. "ssl" might get translated to "-L-lssl"). On Posix platforms dub will try to find the correct linker flags by using pkg-config
        sourceFiles?: string[]                      	// Additional files passed to the compiler - can be useful to add certain configuration dependent source files that are not contained in the general source folder
        sourcePaths?: string[]	                      // Allows to customize the path where to look for source files (any folder "source" or "src" is automatically used as a source path if no sourcePaths setting is specified) - note that you usually also need to define "importPaths" as "sourcePaths" don't influence those
        excludedSourceFiles?: string[]                 // Files that should be removed for the set of already added source files (takes precedence over "sourceFiles" and "sourcePaths") - Glob matching can be used to pattern match multiple files at once
        mainSourceFile?: string                        // Determines the file that contains the main() function. This setting can be used by dub to exclude this file in situations where a different main function is defined (e.g. for "dub test") - this setting does not support platform suffixes
        copyFiles?: string[]                           // A list of globs matching files or directories to be copied to targetPath. Matching directories are copied recursively, i.e. "copyFiles": ["path/to/dir"]" recursively copies dir, while "copyFiles": ["path/to/dir/*"]" only copies files within dir.
        versions?: string[]                            	// A list of D versions to be defined during compilation
        debugVersions?: string[]                       // A list of D debug identifiers to be defined during compilation
        importPaths?: string[]                       	// Additional import paths to search for D modules (the source/ folder is used by default as a source folder, if it exists)
        stringImportPaths?: string[]	                   // Additional import paths to search for string imports/views (the views/ folder is used by default as a string import folder, if it exists)
        preGenerateCommands?: string[]                   	// A list of shell commands that is always executed before project generation is started
        postGenerateCommands?: string[]                 // A list of shell commands that is always executed after project generation is finished
        preBuildCommands?: string[]                       	// A list of shell commands that is executed before the package is built
        postBuildCommands?: string[]                     // A list of shell commands that is executed after the package is built
        preRunCommands?: string[]                        // A list of shell commands that is executed always before the project is run
        postRunCommands?: string[]                       // A list of shell commands that is executed always after the project is run
        dflags?: string[]                               	// Additional flags passed to the D compiler - note that these flags are usually specific to the compiler in use, but a set of flags is automatically translated from DMD to the selected compiler
        lflags?: string
    }

    /** @internal */
    export interface ConvertToTSConfigHost {
        getCurrentDirectory(): string;
        useCaseSensitiveFileNames: boolean;
    }

    /**
     * Generate an uncommented, complete tsconfig for use with "--showConfig"
     * @param configParseResult options to be generated into tsconfig.json
     * @param configFileName name of the parsed config file - output paths will be generated relative to this
     * @param host provides current directory and case sensitivity services
     */
    /** @internal */
    export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig {
        const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames });
        const config = {
            选项: {
                ...arrayFrom(optionMap.entries()).reduce((prev, cur) => ({ ...prev, [cur[0]]: cur[1] }), {}),
                帮助: undefined,
                初始: undefined,
                构建: undefined,
                版本: undefined,
                保留监控输出: undefined,
                文件列表: undefined,
                已输出文件列表: undefined,
            },
            保存时编译: !!configParseResult.保存时编译 ? true : undefined
        };
        return config;
    }

    function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
        if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") {
            // this is of a type CommandLineOptionOfPrimitiveType
            return undefined;
        }
        else if (optionDefinition.type === "list") {
            return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
        }
        else {
            return (<CommandLineOptionOfCustomType>optionDefinition).type;
        }
    }

    function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: Map<string | number>): string | undefined {
        // There is a typeMap associated with this command-line option so use it to map value back to its name
        return forEachEntry(customTypeMap, (mapValue, key) => {
            if (mapValue === value) {
                return key;
            }
        });
    }

    function serializeCompilerOptions(options: CompilerOptions, pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean }): Map<CompilerOptionsValue> {
        const result = createMap<CompilerOptionsValue>();
        const optionsNameMap = getOptionNameMap().optionNameMap;
        const getCanonicalFileName = pathOptions && createGetCanonicalFileName(pathOptions.useCaseSensitiveFileNames);

        for (const name in options) {
            if (hasProperty(options, name)) {
                // tsconfig only options cannot be specified via command line,
                // so we can assume that only types that can appear here string | number | boolean
                if (optionsNameMap.has(name) && optionsNameMap.get(name)!.category === Diagnostics.命令行选项) {
                    continue;
                }
                const value = <CompilerOptionsValue>options[name];
                const optionDefinition = optionsNameMap.get(name.toLowerCase());
                if (optionDefinition) {
                    const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
                    if (!customTypeMap) {
                        // There is no map associated with this compiler option then use the value as-is
                        // This is the case if the value is expect to be string, number, boolean or list of string
                        if (pathOptions && optionDefinition.isFilePath) {
                            result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!));
                        }
                        else {
                            result.set(name, value);
                        }
                    }
                    else {
                        if (optionDefinition.type === "list") {
                            result.set(name, (value as readonly (string | number)[]).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217
                        }
                        else {
                            // There is a typeMap associated with this command-line option so use it to map value back to its name
                            result.set(name, getNameOfCompilerOptionValue(value, customTypeMap));
                        }
                    }
                }
            }
        }
        return result;
    }

    export const enum 配置种类_ {
        Klang,
        KlangModConfig,
    }

    /**
     * Generate tsconfig configuration when running command line "--init"
     * @param options commandlineOptions to be generated into tsconfig.json
     * @param fileNames array of filenames to be generated into tsconfig.json
     */
    /* @internal */
    export function 生成编译或项目配置文件(options: CompilerOptions, 种类: 配置种类_, newLine: string): string {
        const compilerOptions = extend(options, 种类 === 配置种类_.Klang ? defaultInitCompilerOptions : 默认项目配置选项);
        const compilerOptionsMap = serializeCompilerOptions(compilerOptions);
        return writeConfigurations();

        function getDefaultValueForOption(option: CommandLineOption) {
            switch (option.type) {
                case "number":
                    return 1;
                case "boolean":
                    return true;
                case "string":
                    return option.isFilePath ? "./" : "";
                case "list":
                    return [];
                case "object":
                    return {};
                default:
                    const iterResult = option.type.keys().next();
                    if (!iterResult.done) return iterResult.value;
                    return Debug.fail("Expected 'option.type' to have entries.");
            }
        }

        function makePadding(paddingLength: number): string {
            return Array(paddingLength + 1).join(" ");
        }

        function isAllowedOption({ category, name, 是项目配置 }: CommandLineOption, 配置种类: 配置种类_, ): boolean {
            // Skip options which do not have a category or have category `Command_line_Options`
            // Exclude all possible `Advanced_Options` in tsconfig.json which were NOT defined in command line
            return 配置种类 === 配置种类_.Klang ? category !== undefined
                && category !== Diagnostics.命令行选项
                && (category !== Diagnostics.Advanced_Options || compilerOptionsMap.has(name)) && !是项目配置 :
                是项目配置 || false;
        }

        function writeConfigurations() {
            // Filter applicable options to place in the file
            const categorizedOptions = createMultiMap<CommandLineOption>();
            for (const option of buildOpts) {
                const { category } = option;

                if (isAllowedOption(option, 种类)) {
                    categorizedOptions.add(getLocaleSpecificMessage(category!), option);
                }
            }

            // Serialize all options and their descriptions
            let marginLength = 0;
            let seenKnownKeys = 0;
            const nameColumn: string[] = [];
            const descriptionColumn: string[] = [];
            categorizedOptions.forEach((options, category) => {
                if (nameColumn.length !== 0) {
                    nameColumn.push("");
                    descriptionColumn.push("");
                }
                种类 === 配置种类_.Klang ? nameColumn.push(`/* ${category} */`) : undefined;
                种类 === 配置种类_.Klang ? descriptionColumn.push("") : undefined;
                for (const option of options) {
                    let optionName;
                    if (compilerOptionsMap.has(option.name)) {
                        optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`;
                    }
                    else {
                        optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option), undefined, 4)},`;
                    }
                    nameColumn.push(optionName);
                    descriptionColumn.push(`/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */`);
                    marginLength = Math.max(optionName.length, marginLength);
                }
            });
            const result: string[] = [];
            result.push(`{`);
            种类 === 配置种类_.Klang ? result.push(`${makePadding(4)}"编译选项": {`) : undefined;
            // Print out each row, aligning all the descriptions on the same column.
            for (let i = 0; i < nameColumn.length; i++) {
                const optionName = nameColumn[i];
                const description = descriptionColumn[i];
                result.push(optionName && `${种类 === 配置种类_.Klang ? makePadding(8) : makePadding(4)}${optionName}${description && (makePadding(marginLength - optionName.length + 4) + description)}`);
            }
            种类 === 配置种类_.Klang ? result.push(`${makePadding(4)}}`) : undefined;
            result.push(`}`);
            return result.join(newLine) + newLine;
        }
    }

    /* @internal */
    export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAbsolutePath: (path: string) => string) {
        const result: CompilerOptions = {};
        const optionsNameMap = getOptionNameMap().optionNameMap;

        for (const name in options) {
            if (hasProperty(options, name)) {
                result[name] = convertToOptionValueWithAbsolutePaths(
                    optionsNameMap.get(name.toLowerCase()),
                    options[name] as CompilerOptionsValue,
                    toAbsolutePath
                );
            }
        }
        return result;
    }

    function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) {
        if (option) {
            if (option.type === "list") {
                const values = value as readonly (string | number)[];
                if (option.element.isFilePath && values.length) {
                    return values.map(toAbsolutePath);
                }
            }
            else if (option.isFilePath) {
                return toAbsolutePath(value as string);
            }
        }
        return value;
    }

    /**
     * Parse the contents of a config file (tsconfig.json).
     * @param json The contents of the config file to parse
     * @param host Instance of ParseConfigHost used to enumerate files in folder.
     * @param basePath A root directory to resolve relative path entries in the config
     *    file to. e.g. outDir
     */
    export function parseJsonConfigFileContent(json: any, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]): ParsedCommandLine {
        return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, basePath, existingOptions, configFileName, resolutionStack);
    }

    /**
     * Parse the contents of a config file (tsconfig.json).
     * @param jsonNode The contents of the config file to parse
     * @param host Instance of ParseConfigHost used to enumerate files in folder.
     * @param basePath A root directory to resolve relative path entries in the config
     *    file to. e.g. outDir
     */
    export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]): ParsedCommandLine {
        return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, basePath, existingOptions, configFileName, resolutionStack);
    }

    /*@internal*/
    export function setConfigFileInOptions(options: CompilerOptions, configFile: TsConfigSourceFile | undefined) {
        if (configFile) {
            Object.defineProperty(options, "configFile", { enumerable: false, writable: false, value: configFile });
        }
    }

    export function 获取项目文件组(options: CompilerOptions) {
        let fileNames: string[] = [];
        let 根文件组 = options.源码 ? sys.readDirectory(options.源码, supportedTSExtensionsWithJson, [Extension.Dk, Extension.TestK, Extension.Json, Extension.KBuildInfo], [Extension.K], 1) : undefined;
        if (根文件组 && 根文件组.length) {
            fileNames = filter(根文件组, f => fileExtensionIs(f, Extension.K) && !(fileExtensionIs(f, Extension.Dk) || fileExtensionIs(f, Extension.TestK)));
        }
        return fileNames
    }

    function isNullOrUndefined(x: any): x is null | undefined {
        return x === undefined || x === null; // eslint-disable-line no-null/no-null
    }

    /**
     * Parse the contents of a config file from json or json source file (tsconfig.json).
     * @param json The contents of the config file to parse
     * @param sourceFile sourceFile corresponding to the Json
     * @param host Instance of ParseConfigHost used to enumerate files in folder.
     * @param basePath A root directory to resolve relative path entries in the config
     *    file to. e.g. outDir
     * @param resolutionStack Only present for backwards-compatibility. Should be empty.
     */
    function parseJsonConfigFileContentWorker(
        json: any,
        sourceFile: TsConfigSourceFile | undefined,
        basePath: string,
        existingOptions: CompilerOptions = {},
        configFileName?: string,
        resolutionStack: Path[] = []
    ): ParsedCommandLine {
        Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
        const errors: Diagnostic[] = [];

        const parsedConfig = parseConfig(json, sourceFile, basePath, configFileName, resolutionStack, errors);
        const { raw } = parsedConfig;
        const options = extend(existingOptions, parsedConfig.options || {});
        options.configFile = sourceFile
        options.configFilePath = configFileName && normalizeSlashes(configFileName);
        let fileNames = 获取项目文件组(options)
        return {
            options,
            fileNames,
            errors,
            保存时编译: !!raw.保存时编译,
            全局模块位置: sys.getEnvironmentVariable("KLANG_MOD")
        };
    }


    function isErrorNoInputFiles(error: Diagnostic) {
        return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
    }

    function getErrorForNoInputFiles(configFileName: string | undefined) {
        return createCompilerDiagnostic(
            Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
            configFileName || "kconfig.json",
            JSON.stringify([]),
            JSON.stringify([]));
    }
    
    function shouldReportNoInputFiles(result: ExpandResult, canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) {
        return result.fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0);
    }

    /*@internal*/
    export function updateErrorForNoInputFiles(result: ExpandResult, configFileName: string, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) {
        const existingErrors = configParseDiagnostics.length;
        if (shouldReportNoInputFiles(result, canJsonReportNoInutFiles)) {
            configParseDiagnostics.push(getErrorForNoInputFiles(configFileName));
        }
        else {
            filterMutate(configParseDiagnostics, error => !isErrorNoInputFiles(error));
        }
        return existingErrors !== configParseDiagnostics.length;
    }

    

    /**
     * Gets the file names from the provided config file specs that contain, files, include, exclude and
     * other properties needed to resolve the file names
     * @param spec The config file specs extracted with file names to include, wildcards to include/exclude and other details
     * @param basePath The base path for any relative file specifications.
     * @param options Compiler options.
     * @param host The host used to resolve files and directories.
     * @param extraFileExtensions optionaly file extra file extension information from host
     */
    /* @internal */
    export function getFileNamesFromConfigSpecs(options: ParsedCommandLine): ExpandResult {       
        return {
            fileNames: options.fileNames,
        };
    }

    export interface ParsedTsconfig {
        raw: any;
        options?: CompilerOptions;
    }

    /**
     * This *just* extracts options/include/exclude/files out of a config file.
     * It does *not* resolve the included files.
     */
    function parseConfig(
        json: any,
        sourceFile: TsConfigSourceFile | undefined,
        basePath: string,
        configFileName: string | undefined,
        resolutionStack: string[],
        errors: Push<Diagnostic>,
    ): ParsedTsconfig {
        basePath = normalizeSlashes(basePath);
        const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath);

        if (resolutionStack.indexOf(resolvedPath) >= 0) {
            errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> ")));
            return { raw: json || convertToObject(sourceFile!, errors) };
        }

        const ownConfig = json ?
            parseOwnConfigOfJson(json, basePath, configFileName, errors) :
            parseOwnConfigOfJsonSourceFile(sourceFile!, basePath, configFileName, errors);

        return ownConfig;
    }

    function parseOwnConfigOfJson(
        json: any,
        basePath: string,
        configFileName: string | undefined,
        errors: Push<Diagnostic>
    ): ParsedTsconfig {
        const options = convertCompilerOptionsFromJsonWorker(json.编译选项, basePath, errors, configFileName);
        json.保存时编译 = convertCompileOnSaveOptionFromJson(json, basePath, errors);
        return { raw: json, options };
    }

    function parseOwnConfigOfJsonSourceFile(
        sourceFile: TsConfigSourceFile,
        basePath: string,
        configFileName: string | undefined,
        errors: Push<Diagnostic>
    ): ParsedTsconfig {
        const options = getDefaultCompilerOptions(configFileName);
        const optionsIterator: JsonConversionNotifier = {
            onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue) {
                Debug.assert(parentOption === "编译选项");
                const currentOption = options

                currentOption[option.name] = normalizeOptionValue(option, basePath, value);
            }
        };
        const json = convertToObjectWorker(sourceFile, errors, /*returnValue*/ true, getTsconfigRootOptionsMap(), optionsIterator);
        return { raw: json, options };
    }

    function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean {
        if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) {
            return false;
        }
        const result = convertJsonOption(compileOnSaveCommandLineOption, jsonOption.保存时编译, basePath, errors);
        return typeof result === "boolean" && result;
    }

    export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
        const errors: Diagnostic[] = [];
        const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName);
        return { options, errors };
    }

    function getDefaultCompilerOptions(configFileName?: string) {
        const options: CompilerOptions = configFileName && getBaseFileName(configFileName) === "kconfig.json"
            ? { 系统: 'win', 架构: 'amd64', 定义: ['__WIN__'], 输出: './输出' as Path, 源码: './源码' }
            : {};
        return options;
    }

    function convertCompilerOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Push<Diagnostic>, configFileName?: string): CompilerOptions {
        const options = getDefaultCompilerOptions(configFileName);
        convertOptionsFromJson(buildOpts, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
        if (configFileName) {
            options.configFilePath = normalizeSlashes(configFileName);
        }
        return options;
    }


    function convertOptionsFromJson(optionDeclarations: readonly CommandLineOption[], jsonOptions: any, basePath: string,
        defaultOptions: CompilerOptions, diagnosticMessage: DiagnosticMessage, errors: Push<Diagnostic>) {

        if (!jsonOptions) {
            return;
        }

        const optionNameMap = commandLineOptionsToMap(optionDeclarations);

        for (const id in jsonOptions) {
            const opt = optionNameMap.get(id);
            if (opt) {
                defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
            }
            else {
                errors.push(createCompilerDiagnostic(diagnosticMessage, id));
            }
        }
    }

    function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push<Diagnostic>): CompilerOptionsValue {
        if (isCompilerOptionsValue(opt, value)) {
            const optType = opt.type;
            if (optType === "list" && isArray(value)) {
                return convertJsonOptionOfListType(<CommandLineOptionOfListType>opt, value, basePath, errors);
            }
            else if (!isString(optType)) {
                return convertJsonOptionOfCustomType(<CommandLineOptionOfCustomType>opt, <string>value, errors);
            }
            return normalizeNonListOptionValue(opt, basePath, value);
        }
        else {
            errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, getCompilerOptionValueTypeString(opt)));
        }
    }

    function normalizeOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue {
        if (isNullOrUndefined(value)) return undefined;
        if (option.type === "list") {
            const listOption = option;
            if (listOption.element.isFilePath || !isString(listOption.element.type)) {
                return <CompilerOptionsValue>filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => !!v);
            }
            return value;
        }
        else if (!isString(option.type)) {
            return option.type.get(isString(value) ? value.toLowerCase() : value);
        }
        return normalizeNonListOptionValue(option, basePath, value);
    }

    function normalizeNonListOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue {
        if (option.isFilePath) {
            value = getNormalizedAbsolutePath(value, basePath);
            if (value === "") {
                value = ".";
            }
        }
        return value;
    }

    function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) {
        if (isNullOrUndefined(value)) return undefined;
        const key = value.toLowerCase();
        const val = opt.type.get(key);
        if (val !== undefined) {
            return val;
        }
        else {
            errors.push(createCompilerDiagnosticForInvalidCustomType(opt));
        }
    }

    function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: readonly any[], basePath: string, errors: Push<Diagnostic>): any[] {
        return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => !!v);
    }

    function trimString(s: string) {
        return typeof s.trim === "function" ? s.trim() : s.replace(/^[\s]+|[\s]+$/g, "");
    }

    /**
     * Produces a cleaned version of compiler options with personally identifying info (aka, paths) removed.
     * Also converts enum values back to strings.
     */
    /* @internal */
    export function convertCompilerOptionsForTelemetry(opts: CompilerOptions): CompilerOptions {
        const out: CompilerOptions = {};
        for (const key in opts) {
            if (opts.hasOwnProperty(key)) {
                const type = getOptionFromName(key);
                if (type !== undefined) { // Ignore unknown options
                    out[key] = getOptionValueWithEmptyStrings(opts[key], type);
                }
            }
        }
        return out;
    }

    function getOptionValueWithEmptyStrings(value: any, option: CommandLineOption): {} {
        switch (option.type) {
            case "object": // "paths". Can't get any useful information from the value since we blank out strings, so just return "".
                return "";
            case "string": // Could be any arbitrary string -- use empty string instead.
                return "";
            case "number": // Allow numbers, but be sure to check it's actually a number.
                return typeof value === "number" ? value : "";
            case "boolean":
                return typeof value === "boolean" ? value : "";
            case "list":
                const elementType = option.element;
                return isArray(value) ? value.map(v => getOptionValueWithEmptyStrings(v, elementType)) : "";
            default:
                return forEachEntry(option.type, (optionEnumValue, optionStringValue) => {
                    if (optionEnumValue === value) {
                        return optionStringValue;
                    }
                })!; // TODO: GH#18217
        }
    }
}
